import Toast from 'react-native-toast-message';
import StorageUtil from './Storage.ts';
import { navigate } from '../common/navigationService.ts';
import getEnvVars from '../common/env.ts';
import { WX_APPID } from '../common/config.ts';

export interface APIResponseData<T> {
  status: number;
  msg: string;
  total: number;
  data: T;
}

export interface RequestParams {
  [key: string]: any;
}

export interface RequestBody {
  [key: string]: any;
}

const BASE_URL = getEnvVars().API_BASE_URL;

class ApiClient {
  private readonly baseUrl: string;

  constructor(baseUrl: string = BASE_URL!) {
    this.baseUrl = baseUrl;
  }

  private async requestInterceptor(url: string, options: RequestInit): Promise<[string, RequestInit]> {
    const token = await StorageUtil.load('token');
    if (token) {
      options.headers = {
        ...options.headers,
        accessToken: `${token}:${WX_APPID}`,
      };
    }
    return [url, options];
  }

  // 响应拦截
  private async responseInterceptor<T>(response: Response): Promise<APIResponseData<T>> {
    const responseData: APIResponseData<any> = await response.json();
    if (response.ok) {
      if (responseData.status === 0 || responseData.status === 200) {
        return responseData;
      }

      if (responseData.status === 301) {
        Toast.show({ type: 'error', text1: '登录过期，请重新登录' });
        await StorageUtil.remove('token');
        await StorageUtil.remove('userInfo');
        navigate('login');
        return Promise.reject(responseData.msg);
      }

      Toast.show({ type: 'error', text1: responseData.msg || '服务端错误，请联系客服' });
      return Promise.reject(responseData.msg || '服务端错误，请联系客服');
    } else {
      Toast.show({ type: 'error', text1: responseData.msg || '服务端错误，请联系客服' });
      return Promise.reject(responseData.msg || '服务端错误，请联系客服');
    }
  }

  private async request<T>(url: string, options: RequestInit): Promise<APIResponseData<T>> {
    const [interceptedUrl, interceptedOptions] = await this.requestInterceptor(url, options);
    const response = await fetch(interceptedUrl, interceptedOptions);
    return this.responseInterceptor<T>(response);
  }

  private buildQueryString(params: RequestParams): string {
    const query = new URLSearchParams();
    Object.keys(params).forEach((key) => {
      const value = params[key];
      if (Array.isArray(value)) {
        value.forEach((val) => query.append(key, val));
      } else {
        query.append(key, value);
      }
    });
    return query.toString();
  }

  public async get<T>(endpoint: string, params: RequestParams = {}): Promise<APIResponseData<T>> {
    const queryString = this.buildQueryString(params);
    const url = `${this.baseUrl}${endpoint}${queryString ? `?${queryString}` : ''}`;

    const options: RequestInit = {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      },
    };
    return this.request<T>(url, options);
  }

  public async post<T>(endpoint: string, body: RequestBody = {}): Promise<APIResponseData<T>> {
    const options: RequestInit = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(body),
    };
    return this.request<T>(`${this.baseUrl}${endpoint}`, options);
  }

  public async put<T>(endpoint: string, body: RequestBody = {}): Promise<APIResponseData<T>> {
    const options: RequestInit = {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(body),
    };

    return this.request<T>(`${this.baseUrl}${endpoint}`, options);
  }

  public async delete<T>(endpoint: string): Promise<APIResponseData<T>> {
    const options: RequestInit = {
      method: 'DELETE',
      headers: {
        'Content-Type': 'application/json',
      },
    };

    return this.request<T>(`${this.baseUrl}${endpoint}`, options);
  }
}

export default new ApiClient();
